package easy

import (
	"reflect"
	"strconv"
)

func NameID(t reflect.Type, titles *[]string, paths *[][]int, parent []int) {
	for kind := t.Kind(); kind == reflect.Ptr || kind == reflect.Slice || kind == reflect.Array; kind = t.Kind() {
		t = t.Elem()
	}

	if t.Kind() != reflect.Struct {
		return
	}
	//log.Println(prefix + t.String())
	for i := 0; i < t.NumField(); i++ {
		path := parent
		path = append(path, i)
		fieldType := t.Field(i)
		typ := fieldType.Type
		if typ.Kind() == reflect.Ptr {
			typ = typ.Elem()
		}
		if fieldType.Anonymous {
			if typ.Kind() == reflect.Struct {
				tag := fieldType.Tag.Get("json")
				if tag == "-" {
					continue
				}
				NameID(typ, titles, paths, path)
			}
			continue
		}
		if typ.Kind() == reflect.Struct {
			tag := fieldType.Tag.Get("json")
			if tag == "-" {
				continue
			}
			if fieldType.IsExported() {
				NameID(typ, titles, paths, path)
			}
			continue
		}

		if fieldType.IsExported() {
			*titles = append(*titles, fieldType.Name)
			*paths = append(*paths, path)
		}
	}
}

func ValueToString(field reflect.Value, fstring func(string) string) string {
	kind := field.Type().Kind()
	tt := field.Type()
	if kind == reflect.Ptr {
		tt = tt.Elem()
		kind = tt.Kind()
		field = field.Elem()
	}
	if !(IsNumber(tt) || IsString(tt)) {
		return ""
	}
	if !field.IsValid() {
		return ""
	}
	switch kind {
	case reflect.Bool:
		if field.Bool() {
			return "1"
		} else {
			return "0"
		}
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return strconv.FormatInt(field.Int(), 10)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return strconv.FormatUint(field.Uint(), 10)
	case reflect.Float32, reflect.Float64:
		return Ftoa(field.Float())
	case reflect.String:
		//, 替换 &#044;
		//\n 替换 &#010;
		if fstring != nil {
			return fstring(field.String())
		}
		return field.String()
	}
	return ""
}

func ValueFromString(val string, field reflect.Value, fstring func(string) string) (err error) {
	kind := field.Type().Kind()
	tt := field.Type()
	if kind == reflect.Ptr {
		if field.IsNil() {
			field.Set(reflect.New(tt.Elem()))
		}
		tt = tt.Elem()
		kind = tt.Kind()
		field = field.Elem()
	}
	if !(IsNumber(tt) || IsString(tt)) {
		return
	}
	if !field.IsValid() {
		return
	}
	switch kind {
	case reflect.Bool:
		field.SetBool(BoolValue(val))
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		v, err := strconv.ParseInt(val, 10, 64)
		if err != nil {
			return err
		}
		field.SetInt(v)
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		v, err := strconv.ParseUint(val, 10, 64)
		if err != nil {
			return err
		}
		field.SetUint(v)
	case reflect.Float32, reflect.Float64:
		v, err := strconv.ParseFloat(val, 64)
		if err != nil {
			return err
		}
		field.SetFloat(v)
	case reflect.String:
		//, 替换 &#044;
		//\n 替换 &#010;
		//return field.String()
		if fstring != nil {
			val = fstring(val)
		}
		field.SetString(val)
	}
	return
}

// 是否是数字
func IsNumber(t reflect.Type) bool {
	kind := t.Kind()
	if kind >= reflect.Bool && kind <= reflect.Float64 {
		return true
	}
	return false
}

// 是否是字符串
func IsString(t reflect.Type) bool {
	return reflect.String == t.Kind()
}
